﻿


using IotContract.Dtos.Clients;
using IotContract.Dtos.Servers.Pushs;
using IotContract.Enums;
using IotContract.Interfaces;
using IotContract.Models.Clients;
using IotContract.Models.Mqtt;
using Mapster;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XT.Common.Extensions;


namespace IotServerService.Services.Datas.Managers;
/// <summary>
/// 设备数据管理，根据协议区分
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class ServerDataBaseManager<T> : IServerDataManager where T : PushEquipDto
{
    /// <summary>
    /// 设备数据
    /// </summary>
    private ConcurrentDictionary<long, T> _equipDic = new ConcurrentDictionary<long, T>();
    /// <summary>
    /// 写入命令数据
    /// </summary>
    private ConcurrentDictionary<long, ConcurrentQueue<OperationWriteCommand>> _equipWriteDic = new ConcurrentDictionary<long, ConcurrentQueue<OperationWriteCommand>>();
    /// <summary>
    /// 设备报警弹窗数据,设备报警根据协议进行区分,报警为设备数据报警，非API调用报警（API报警再API项目中），如火警等
    /// 报警数据消费依赖于调度程序，目前消费内部是通过SignalR发布。
    /// </summary>
    private ConcurrentDictionary<long, ConcurrentQueue<IotEquipWarnDto>> _warnDic = new ConcurrentDictionary<long, ConcurrentQueue<IotEquipWarnDto>>();
    /// <summary>
    /// 协议
    /// </summary>
    public abstract string ProtobufType { get; set; }
    /// <summary>
    /// 添加写入命令
    /// </summary>
    /// <param name="command"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public virtual async Task<bool> AddWrite(OperationWriteCommand command)
    {
       if (_equipWriteDic.ContainsKey(command.EquipId))
        {
           var queue= _equipWriteDic.GetValueOrDefault(command.EquipId);
            queue.Enqueue(command);
        }
        else
        {
            ConcurrentQueue<OperationWriteCommand> newqueue = new ConcurrentQueue<OperationWriteCommand>();
            newqueue.Enqueue(command);
            _equipWriteDic.TryAdd(command.EquipId, newqueue);
        }
      
        return true;
    }
    /// <summary>
    /// 添加写入命令
    /// </summary>
    /// <param name="command"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public virtual async Task<bool> AddWrites(IEnumerable<OperationWriteCommand> commands)
    {
        foreach (var command in commands)
        {
          await  AddWrite(command);

        }
        return true;
    }

    /// <summary>
    /// 添加报警
    /// </summary>
    /// <param name="warns"></param>
    /// <returns></returns>
    public virtual async Task<bool> AddWarns(IEnumerable<IotEquipWarnDto> warns)
    {
        foreach (var warn in warns)
        {
            ConcurrentQueue<IotEquipWarnDto> queue = new ConcurrentQueue<IotEquipWarnDto>();
            if (!_warnDic.ContainsKey(warn.EquipId))
            {
                queue.Enqueue(warn);
                _warnDic.TryAdd(warn.EquipId, queue);
            }
            else
            {
                var okqueue = _warnDic.GetValueOrDefault(warn.EquipId);
                if (okqueue != null)
                {
                    // 10个足够
                    if (okqueue.Count > 10)
                    {
                        okqueue.TryDequeue(out _);
                    }
                    okqueue.Enqueue(warn);
                }
            }

        }
        return true;
    }

    /// <summary>
    /// 获取设备数据
    /// </summary>
    /// <param name="command"></param>
    /// <returns></returns>
    public virtual async Task<List<IPushEquip>> GetEquips(ClientRequestCommand command)
    {
        List<IPushEquip> equipList = new List<IPushEquip>();
        if (command.EquipId > 0)
        {
            //直接获取设备
            var equip = _equipDic.GetValueOrDefault(command.EquipId);
            if (equip != null)
            {
                equipList.Add(equip);
            }
        }
        else if (command.ProgramId > 0)
        {
            var datas = _equipDic.Values.Where(x => x.ProgramId == command.ProgramId);
            if (datas != null && datas.Count() > 0)
            {
                equipList.AddRange(datas);
            }
        }
        else if (command.RequestType.IsNotNullOrEmpty())
        {
            // 除充放电库位以外的全部数据
            if (command.RequestType == "1")
            {
                equipList.AddRange(_equipDic.Values.Where(x => x.EquipType != IotEquipType.FMT.ToString() || x.EquipType != IotEquipType.CAPACITY.ToString()));
            }
            else
            {
                var datas = _equipDic.Values.Where(x => x.EquipType == command.RequestType);
                if (datas != null && datas.Count() > 0)
                {
                    equipList.AddRange(datas);
                }
            }
        }
        return equipList;
    }

    /// <summary>
    /// 获取设备数据
    /// </summary>
    /// <param name="command"></param>
    /// <returns></returns>
    public virtual async Task<List<IPushEquip>> GetEquips(List<ClientRequestCommand> commands)
    {
        List<IPushEquip> equipList = new List<IPushEquip>();
        foreach (var command in commands)
        {
            equipList.AddRange(await GetEquips(command));
        }
        return equipList;
    }


    /// <summary>
    /// 添加设备数据
    /// </summary>
    /// <param name="equipList"></param>
    /// <returns></returns>
    public virtual async Task<List<OperationWriteCommand>> PushEquips(List<IPushEquip> equipList)
    {
      
            if (equipList == null || equipList.Count == 0) return new List<OperationWriteCommand>();
            List<OperationWriteCommand> commands = new List<OperationWriteCommand>();
            foreach (var data in equipList)
            {
                if (_equipDic.ContainsKey(data.Id))
                {
                    _equipDic[data.Id] = data as T;
                }
                else
                {
                    _equipDic.TryAdd(data.Id, data as T);
                }
                ConcurrentQueue<OperationWriteCommand> writes = _equipWriteDic.GetValueOrDefault(data.Id);
                if (writes == null)
                {
                    continue;
                }

                bool result = true;
                do
                {

                    result = writes.TryDequeue(out var command);
                    if (command != null)
                    {
                        commands.Add(command);
                    }
                }
                while (result);

            }



            return commands;
     
    }
    /// <summary>
    /// 清理数据
    /// </summary>
    /// <returns></returns>
    public async Task ClearEquips()
    {
        _equipDic.Clear();
        _warnDic.Clear();
        _equipWriteDic.Clear();
    }
}
